package com.fjxd.planeTicket.web;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fjxd.feign.clients.CityClient;
import com.fjxd.feign.clients.FlightNumberClient;
import com.fjxd.feign.clients.PlaneClient;
import com.fjxd.feign.pojo.City;
import com.fjxd.feign.pojo.FlightNumber;
import com.fjxd.feign.pojo.Plane;
import com.fjxd.feign.result.ViewResult;
import com.fjxd.planeTicket.pojo.Ticket;
import com.fjxd.planeTicket.service.PlaneTicketService;
import com.fjxd.planeTicket.vo.TicketVo;
import com.fjxd.planeTicket.vo.ViewTicket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author csw
 *查询机票
 */

@CrossOrigin
@Slf4j
@RestController
@RequestMapping("/planeTicketQuery")
public class PlaneTicketController {
    final PlaneTicketService planeTicketService;
    final PlaneClient planeClient;
    final CityClient cityClient;
    final FlightNumberClient flightNumberClient;
    protected static final Integer FLIGHT_NUMBER_MIN_NUM = 2;
    final StringRedisTemplate redisTemplate;
    protected static final double DISTANCE_MULTIPLE = 1.5;
    private double discount;

    public double getDiscount() {
        return discount;
    }

    public void setDiscount(double discount) {
        this.discount = discount;
    }




    public PlaneTicketController(PlaneTicketService planeTicketService,
                                 PlaneClient planeClient,
                                 CityClient cityClient,
                                 FlightNumberClient flightNumberClient, StringRedisTemplate redisTemplate) {
        this.planeTicketService = planeTicketService;
        this.planeClient = planeClient;
        this.cityClient = cityClient;
        this.flightNumberClient = flightNumberClient;
        this.redisTemplate = redisTemplate;
    }


    /**
     * 通过出发日期 出发城市 降落城市查询满足条件的机票
     *
     * @param startDate 出发日期
     * @param upCity    出发城市
     * @param downCity  降落城市
     * @return 返会vTicket对象数组
     */
    @GetMapping("/queryTicket/{startDate}/{upCity}/{downCity}")
    public ViewResult queryTicket(@PathVariable String startDate,
                                  @PathVariable String upCity,
                                  @PathVariable String downCity) {

        if (upCity.equals(downCity)) {
            return new ViewResult(
                    ViewResult.Status.SERVERERROR.getCode(),
                    "暂不支持同城查询");
        }
        Date parse1 = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            parse1 = simpleDateFormat.parse(startDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        assert parse1 != null;
        if (parse1.before(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24))) {
            return ViewResult.success();
        }
        List<Ticket> tickets = new ArrayList<>();
        List<Integer> cityIdListByName = new ArrayList<>();
        citySingle(upCity, downCity, cityIdListByName);
        //通过查询的城市id获取航班号id
        List<Integer> flightNumberIdByCityId = flightNumberClient
                .getFlightNumberIdByCity(upCity,
                        downCity);

        String key = startDate + ":" + cityIdListByName.get(0) + cityIdListByName.get(1);
        String jsonPlanTicket = redisTemplate.opsForValue().get(key);

        if (StrUtil.isNotBlank(jsonPlanTicket)) {
            tickets.addAll(JSONUtil.toList(jsonPlanTicket, Ticket.class));
            return ViewResult.success(tickets);
        }

        flightNumberIdByCityId.forEach(flightNumber -> {
            Ticket ticketByFlightNumberId = planeTicketService
                    .getTicketByFlightNumberId(flightNumber, startDate);
            pTicket(tickets, ticketByFlightNumberId, startDate);
        });

        if (tickets.size() <= 0) {
            return new ViewResult(404, "请求数据为空");
        }

        redisTemplate.opsForValue().set(key, JSONUtil.toJsonPrettyStr(tickets), 1L, TimeUnit.MINUTES);

        return ViewResult.success(tickets);

    }

    private void citySingle(String upCity, String downCity, List<Integer> cityIdListByName) {
        List<City> cityId = cityClient.getCityIdListByName(upCity, downCity);
        List<City> cities = cityClient.getCityIdListByName(upCity, downCity);
        cityId.forEach(c -> {
            if (cityIdListByName.size() == 0) {
                cityIdListByName.add(c.getId());
                cities.add(c);
            } else {
                if (!cityId.get(0).getName().equals(c.getName())) {
                    cityIdListByName.add(c.getId());
                    cities.add(c);
                }
            }
        });
        double trafficWas = cities.get(0).getTrafficWas() + cities.get(1).getTrafficWas();
        if (trafficWas > 60) {
            setDiscount(0.2);
        } else if (trafficWas > 50) {
            setDiscount(0.3);
        } else if (trafficWas > 40) {
            setDiscount(0.4);
        } else if (trafficWas > 30) {
            setDiscount(0.5);
        } else if (trafficWas > 20) {
            setDiscount(0.6);
        } else {
            setDiscount(0.7);
        }
    }


    /**
     * @param upDate         出发日期
     * @param flightNumberId 航班号Id
     * @return 返会vTicket对象数组
     */
    @GetMapping("/queryTicket/{upDate}/{flightNumberId}")
    public ViewResult queryTicket1(@PathVariable String upDate,
                                   @PathVariable Integer flightNumberId) {

        List<Ticket> tickets = new ArrayList<>();
        DateTime startDate = DateUtil.parse(upDate);
        planeTicketService.getTicketFlightNumberId(flightNumberId)
                .forEach((Ticket ticket) -> {
                    DateTime ticketStartDate = DateUtil.parse(ticket.getStartDate());
                    if (DateUtil.between(ticketStartDate, startDate, DateUnit.DAY) == 0) {
                        pTicket(tickets, ticket, upDate);
                    }
                });
        return ViewResult.success(tickets);
    }

    @PostMapping("/transfersTicket/{upDate}/{upCity}/{downCity}")
    public ViewResult transfers(@PathVariable String upDate,
                                @PathVariable String upCity,
                                @PathVariable String downCity,
                                @RequestParam(required = false, defaultValue = "0") Integer startIndex,
                                @RequestParam(required = false, defaultValue = "30") Integer size) {
        DateFormat dfTime = new SimpleDateFormat("HH:mm");
        List<ViewTicket> viewTickets = new ArrayList<>();
        if (DateUtil.parse(upDate).before(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24))) {
            return new ViewResult();
        } else if (upCity.equals(downCity)) {
            return new ViewResult(500, "暂不支持同城");
        } else {
            List<Integer> cityIdListByName = new ArrayList<>();
            citySingle(upCity, downCity, cityIdListByName);
            List<FlightNumber> flightNumberByUpCityId = flightNumberClient
                    .getFlightNumberByUpCityIdAndDownCityId(cityIdListByName.get(0),
                            cityIdListByName.get(1), startIndex, size);
            List<FlightNumber> flightNumberByDownCityId = flightNumberClient
                    .getFlightNumberIdByDownCityId(cityIdListByName.get(1));
            List<Integer> flightNumberIdByCityId = flightNumberClient
                    .getFlightNumberIdByCity(upCity, downCity);
            FlightNumber nonstop = flightNumberClient
                    .getFlightNumberById(flightNumberIdByCityId.get(0));
            flightNumberByUpCityId.forEach(transfers1 -> {
                List<Integer> flightNumberId = new ArrayList<>();
                for (FlightNumber transfers2 : flightNumberByDownCityId) {
                    if(Objects.equals(transfers1.getDownCityId(), transfers2.getUpCityId())){
                        if (nonstop.getDistance() * DISTANCE_MULTIPLE >
                                transfers1.getDistance() + transfers2.getDistance()) {
                            try {
                                if (dfTime.parse(transfers1.getEndTime()).getTime()+dfTime.parse("09:00").getTime() <
                                        dfTime.parse(transfers2.getStarTime()).getTime()) {
                                    flightNumberId.add(transfers1.getId());
                                    flightNumberId.add(transfers2.getId());
                                    break;
                                }
                            } catch (ParseException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
                if (flightNumberId.size() >= FLIGHT_NUMBER_MIN_NUM) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    ViewTicket viewTicket = new ViewTicket();
                    List<Ticket> ticketList = new ArrayList<>();
                    pTicket(ticketList, planeTicketService
                            .getTicketByFlightNumberId(flightNumberId.get(0), upDate), upDate);
                    try {
                        if(dfTime.parse(flightNumberClient.getFlightNumberById(flightNumberId.get(1)).getStarTime()).getTime()<=dfTime.parse("08:00").getTime()){
                            Date parse = simpleDateFormat.parse(upDate);
                            ZoneId zoneId = ZoneId.systemDefault();
                            LocalDateTime localDateTime = LocalDateTime.ofInstant(parse.toInstant(), zoneId).plusDays(1);
                            ZonedDateTime zdt = localDateTime.atZone(zoneId);
                            Date date = Date.from(zdt.toInstant());
                            String startDate = simpleDateFormat.format(date);
                            pTicket(ticketList, planeTicketService
                                    .getTicketByFlightNumberId(flightNumberId.get(1), startDate), startDate);
                        }else{
                            pTicket(ticketList, planeTicketService
                                    .getTicketByFlightNumberId(flightNumberId.get(1), upDate), upDate);
                        }

                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    if (ticketList.size() > 1) {
                        viewTicket.setTickets(ticketList);
                        viewTickets.add(viewTicket);
                    }
                }
            });
        }
        return ViewResult.success(viewTickets);
    }



    @GetMapping("/multistageTicket/{upDate}/{upCity}/{downCity}")
    public ViewResult multistage(@PathVariable("upDate") String upDate,
                                 @PathVariable("upCity") String upCity,
                                 @PathVariable("downCity") String downCity) {
        String [] upDateList = upDate.split("_");
        String [] upCityList = upCity.split("_");
        String [] downCityList = downCity.split("_");
        List<Object> data = new ArrayList<>();
        for (int i = 0; i < upDateList.length; i++) {
            Object data1 = queryTicket(upDateList[i], upCityList[i], downCityList[i]).getData();
            data.add(data1);
        }
        return ViewResult.success(data);
    }


    private void pTicket(List<Ticket> tickets, Ticket ticket, String startDate) {
        DateFormat dfTime = new SimpleDateFormat("HH:mm");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String newDate = simpleDateFormat.format(new Date());
        double discount = getDiscount();
        String format = dfTime.format(new Date());
        String[] split = format.split(":");
        String[] split1 = ticket.getStartTime().split(":");
        if(newDate.equals(startDate)){
            if(Integer.parseInt(split[0])<Integer.parseInt(split1[0])){
                discount(ticket, tickets, startDate, discount);
            }
        }else{
            discount(ticket, tickets, startDate, discount);
        }
    }


    private void discount(Ticket ticket, List<Ticket> tickets, String startDate, double discount) {
        Date start = DateUtil.parse(DateUtil.now());
        Date end = DateUtil.parse(startDate);
        String[] split = ticket.getStartTime().split(":");
        int time = Integer.parseInt(split[0]);
        double economyPrice = ticket.getEconomyPrice();
        long days = DateUtil.between(start, end, DateUnit.DAY);
        if (days >= 45) {
            ticket.setDiscountPrice(timeDiscount(time, discount, economyPrice,ticket));
            tickets.add(ticket);
        } else if (days >= 30) {
            ticket.setDiscountPrice(timeDiscount(time, discount + 0.005, economyPrice,ticket));
            tickets.add(ticket);
        } else if (days >= 15) {
            ticket.setDiscountPrice(timeDiscount(time, discount + 0.025, economyPrice,ticket));
            tickets.add(ticket);
        } else if (days >= 7) {
            ticket.setDiscountPrice(timeDiscount(time, discount + 0.05, economyPrice,ticket));
            tickets.add(ticket);
        } else if (days == 2) {
            ticket.setDiscountPrice(timeDiscount(time, discount + 0.3, economyPrice,ticket));
            tickets.add(ticket);
        } else if (days == 1){
            ticket.setDiscountPrice(timeDiscount(time, discount + 0.5, economyPrice,ticket));
            tickets.add(ticket);
        }else {
            ticket.setDiscountPrice(timeDiscount(time, discount + 0.1, economyPrice,ticket));
            tickets.add(ticket);
        }
    }

    private double timeDiscount(int time, double cityDiscount, double economyPrice,Ticket ticket) {
        if (time <= 8) {
            ticket.setDiscountClass((cityDiscount + 0.02) * 10);
            return Math.ceil(economyPrice * (cityDiscount + 0.02));
        }

        if (time <= 10) {
            ticket.setDiscountClass((cityDiscount+0.05) * 10);
            return Math.ceil(economyPrice * (cityDiscount + 0.05));
        }

        if (time >= 21) {
            ticket.setDiscountClass((cityDiscount - 0.02) * 10);
            return Math.ceil(economyPrice * (cityDiscount - 0.02));
        }
        if (time <= 16) {
            ticket.setDiscountClass((cityDiscount + 0.2) * 10);
            return Math.ceil(economyPrice * (cityDiscount + 0.2));

        } else {
            ticket.setDiscountClass(cityDiscount * 10);
            return Math.ceil(economyPrice * cityDiscount);
        }
    }


    /**
     * @return 返回所有机票数据
     */
    @GetMapping("/getAll")
    public List<Ticket> getALlTicket() {
        return planeTicketService.list();
    }

    /**
     * 通过机票id获取机票
     */
    @GetMapping("/getTicket/{id}")
    public Ticket getTicketId(@PathVariable Integer id) {
        Ticket tbyId = planeTicketService.getById(id);
        FlightNumber flightNumberById = flightNumberClient.getFlightNumberById(tbyId.getFId());
        System.out.println(flightNumberById);
//        tbyId.setFlightNumber(flightNumberById);

        return tbyId;
    }


    /**
     * 模拟生成当月剩余时间机票
     * @return 返会是否成功
     */
    @PostMapping("/saveTicket")
    public ViewResult test1(){
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        //一年每一个月多少天
        int[] month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        //判断闰年
        int year = calendar.get(Calendar.YEAR);
        if ((year % 4 == 0) && ((year % 100) != 0)) {
            month[1] = 29;
        } else if (year % 100 == 0 && year % 400 == 0) {
            month[1] = 29;
        }
        List<Ticket> tickets = new ArrayList<>();
        //int day = month[calendar.get(Calendar.MONTH)] - calendar.get(Calendar.DAY_OF_MONTH);
        int day = 60;
        IntStream.rangeClosed(1, day).forEach(finalI -> flightNumberClient.getAll().forEach((flightNumber) -> {
            Ticket ticket = new Ticket();
            Plane planeById = planeClient.getPlaneById(flightNumber.getPId());
            ticket.setPId(planeById.getId());
            ticket.setFId(flightNumber.getId());
            ticket.setFirstPrice(flightNumber.getDistance() * 3);
            ticket.setBusinessPrice(flightNumber.getDistance() * 2);
            ticket.setEconomyPrice(flightNumber.getDistance() * 1.5);
            Date endTime = new Date(date.getTime() + 1000L * 60 * 60 * 24 * finalI);
            String format = df.format(endTime);
            ticket.setStartTime(flightNumber.getStarTime());
            ticket.setStartDate(format);
            ticket.setCompany(planeById.getAirlines().getName());
            ticket.setCompanyLogos(planeById.getAirlines().getLogos());
            ticket.setSailingTime(flightNumber.getSailingTime());
            ticket.setFName(flightNumber.getFlightNumber());
            ticket.setPName(planeById.getName());
            ticket.setUpCity(flightNumber.getUpCity());
            ticket.setDownCity(flightNumber.getDownCity());
            String[] split = flightNumber.getEndTime().split(":");
            int time = Integer.parseInt(split[0]);
            if (time < 8) {
                ticket.setEndTime(flightNumber.getEndTime());
            } else if (finalI <= month[calendar.get(Calendar.MONTH)]) {
                ticket.setEndTime(flightNumber.getEndTime());
            } else {
                ticket.setEndTime(flightNumber.getEndTime());
            }
            tickets.add(ticket);
        }));
        planeTicketService.saveBatch(tickets);
        return ViewResult.success();
    }

    @GetMapping("/getPlaneByFid/{fid}")
    public Ticket getPlaneByFid(@PathVariable Integer fid){
        Ticket ticket = planeTicketService.getPlaneByFid(fid);
        List<Integer> cityIdListByName = new ArrayList<>();
        citySingle(ticket.getUpCity(), ticket.getDownCity(), cityIdListByName);
        System.out.println(getDiscount());
        List<Ticket> tickets = new ArrayList<>();
        pTicket(tickets, ticket, ticket.getStartDate());
        return ticket;
    }

}
